package com.example.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.PageResult;
import com.example.common.enums.ErrorCodeEnum;
import com.example.common.enums.PostStatusEnum;
import com.example.common.enums.RoleEnum;
import com.example.exception.CustomException;
import com.example.mapper.PostMapper;
import com.example.pojo.dto.PostQueryDto;
import com.example.pojo.entity.Account;
import com.example.pojo.entity.Comment;
import com.example.pojo.entity.Post;
import com.example.pojo.entity.User;
import com.example.pojo.vo.PostQueryVo;
import com.example.utils.AccountUtils;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 帖子 service 层实现类
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {

    @Resource
    private UserService userService;

    @Resource
    @Lazy
    private CommentService commentService;

    /**
     * 普通用户发布帖子
     *
     * @param post 帖子
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createPost(Post post) {
        // 1.校验参数
        if (post == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        if (StrUtil.isBlank(post.getTitle())) {
            throw new CustomException(ErrorCodeEnum.POST_TITLE_LOSE);
        }
        if (StrUtil.isBlank(post.getContent())) {
            throw new CustomException(ErrorCodeEnum.POST_CONTENT_LOSE);
        }
        if (StrUtil.isBlank(post.getImage())) {
            throw new CustomException(ErrorCodeEnum.POST_IMAGE_LOSE);
        }

        // 2.校验角色，只有普通用户才可以发布帖子
        User dbUser = this.checkUserRole();

        // 3.构建参数
        // 前端传了帖子标题、帖子内容、帖子封面图片
        // 3.1 普通用户id
        post.setUserId(dbUser.getId());
        // 3.2 发布时间
        post.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        // 3.3 浏览量 = 0
        post.setViewCount(0);
        // 3.4 审核状态
        post.setStatus(PostStatusEnum.AUDIT.getName());

        // 4.存入数据库
        this.save(post);
    }

    /**
     * 分页查询帖子
     *
     * @param dto 条件
     * @return 分页结果
     */
    @Override
    public PageResult<PostQueryVo> pageQuery(PostQueryDto dto) {
        // 1.校验参数
        if (dto.getPageNum() == null || dto.getPageNum() < 1) {
            throw new CustomException(ErrorCodeEnum.PAGE_QUERY_NUM);
        }
        if (dto.getPageSize() == null || dto.getPageSize() < 1 || dto.getPageSize() > 100) {
            throw new CustomException(ErrorCodeEnum.PAGE_QUERY_SIZE);
        }

        // 2.校验角色
        this.checkUserAndAdmin();

        // 3.创建 MybatisPlus 分页对象
        IPage<PostQueryVo> pageObject = new Page<>(dto.getPageNum(), dto.getPageSize());

        // 4.分页查询帖子
        pageObject = this.getBaseMapper().pageQuery(pageObject, dto);

        // 5.构建分页结果并返回
        return new PageResult<>(
                pageObject.getTotal(),
                pageObject.getRecords()
        );
    }

    /**
     * 分页查询当前普通用户自己的帖子
     *
     * @param dto 条件
     * @return 分页结果
     */
    @Override
    public PageResult<PostQueryVo> pageQueryPerson(PostQueryDto dto) {
        // 1.校验参数
        if (dto == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.校验角色
        User dbUser = this.checkUserRole();

        // 3.根据普通用户 id 分页查询帖子
        dto.setUserId(dbUser.getId());
        return this.pageQuery(dto);
    }

    /**
     * 分页查询宠物论坛帖子
     *
     * @param dto 条件
     * @return 分页结果
     */
    @Override
    public PageResult<PostQueryVo> pageQueryForumPost(PostQueryDto dto) {
        // 1.校验参数
        if (dto == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.校验角色
        this.checkUserRole();

        // 3.分页查询帖子状态一定是"审核通过"
        dto.setStatus(PostStatusEnum.AUDIT_SUCCESS.getName());
        return this.pageQuery(dto);
    }

    /**
     * 根据帖子id查询帖子详情
     *
     * @param id 帖子id
     * @return 帖子详情
     */
    @Override
    public PostQueryVo queryPostDetail(Integer id) {
        // 1.校验参数
        if (id == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.校验角色
        this.checkUserRole();

        // 3.根据帖子id查询帖子
        PostQueryVo vo = this.getBaseMapper().queryPostDetail(id);

        // 帖子不存在
        if (vo == null) {
            throw new CustomException(ErrorCodeEnum.POST_NOT_EXITS);
        }

        // 只能查看审核通过的帖子
        if (!PostStatusEnum.AUDIT_SUCCESS.getName().equals(vo.getStatus())) {
            throw new CustomException(ErrorCodeEnum.ONLY_QUERY_AUDIT_SUCCESS);
        }

        // 4.返回帖子详情
        return vo;
    }

    /**
     * 增加帖子浏览量
     *
     * @param id 帖子id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addPostViewCount(Integer id) {
        // 1.校验参数
        if (id == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.校验角色
        this.checkUserRole();

        // 3.帖子浏览量 + 1
        Post dbPost = this.lambdaQuery()
                .eq(Post::getId, id)
                .one();
        if (dbPost == null) {
            throw new CustomException(ErrorCodeEnum.POST_NOT_EXITS);
        }
        this.lambdaUpdate()
                .eq(Post::getId, id)
                .set(Post::getViewCount, dbPost.getViewCount() + 1)
                .update();
    }

    /**
     * 管理员审核帖子
     *
     * @param post 帖子
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditPost(Post post) {
        // 1.校验参数
        if (post == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        if (post.getId() == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        // 2.校验角色
        this.checkAdminRole();
        // 3.根据帖子id更新帖子
        this.updateById(post);
    }

    /**
     * 普通用户修改帖子
     *
     * @param post 帖子id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Post post) {
        // 1.校验参数
        if (post == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        if (post.getId() == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        // 2.校验角色
        this.checkUserRole();
        // 3.普通用户修改帖子，帖子状态变为"待审核"
        post.setStatus(PostStatusEnum.AUDIT.getName());
        // 4.根据帖子id更新帖子
        this.updateById(post);
    }

    /**
     * 根据帖子id删除帖子
     *
     * @param id 帖子id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id) {
        // 1.校验参数
        if (id == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        // 2.校验角色
        this.checkUserAndAdmin();

        // 3.根据帖子id查出帖子所有评论
        List<Integer> commentIdList = this.commentService.lambdaQuery()
                .eq(Comment::getPostId, id)
                .isNull(Comment::getParentId)
                .list()
                .stream()
                .map(Comment::getId)
                .toList();

        // 4.根据评论id删除评论及其回复
        if (CollectionUtil.isNotEmpty(commentIdList)) {
            for (Integer commentId : commentIdList) {
                this.deleteComment(commentId);
            }
        }

        // 5.根据帖子id删除帖子
        this.removeById(id);
    }

    /**
     * 根据帖子id列表删除帖子
     *
     * @param ids 帖子id列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(List<Integer> ids) {
        // 1.校验参数
        if (CollectionUtil.isEmpty(ids)) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        // 2.校验角色
        this.checkUserAndAdmin();

        // 3.根据帖子id列表查出帖子所有评论
        List<Integer> commentIdList = this.commentService.lambdaQuery()
                .in(Comment::getPostId, ids)
                .isNull(Comment::getParentId)
                .list()
                .stream()
                .map(Comment::getId)
                .toList();

        // 4.根据评论id删除评论及其回复
        if (CollectionUtil.isNotEmpty(commentIdList)) {
            for (Integer commentId : commentIdList) {
                this.deleteComment(commentId);
            }
        }

        // 5.根据帖子id列表删除帖子
        this.removeBatchByIds(ids);
    }

    /**
     * 删除评论及其回复
     *
     * @param commentId 评论id
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteComment(Integer commentId) {
        // 1.删除评论
        this.commentService.removeById(commentId);
        // 2.查询回复
        List<Comment> commentList = this.commentService.lambdaQuery()
                .eq(Comment::getParentId, commentId)
                .list();
        // 3.没有回复则返回
        if (CollectionUtil.isEmpty(commentList)) {
            return;
        }
        // 4.有回复则继续删除
        for (Comment comment : commentList) {
            deleteComment(comment.getId());
        }
    }

    /**
     * 校验角色是否是普通用户或管理员
     */
    private void checkUserAndAdmin() {
        Account currentLoginAccount = AccountUtils.getCurrentLoginAccount();
        if (currentLoginAccount == null) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        if (!RoleEnum.USER.name().equals(currentLoginAccount.getRole()) && !RoleEnum.ADMIN.name().equals(currentLoginAccount.getRole())) {
            throw new CustomException(ErrorCodeEnum.ONLY_USER_OR_ADMIN_POST);
        }
    }

    /**
     * 校验角色是否是普通用户
     *
     * @return 普通用户
     */
    private User checkUserRole() {
        Account currentLoginAccount = AccountUtils.getCurrentLoginAccount();
        if (currentLoginAccount == null) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        if (!RoleEnum.USER.name().equals(currentLoginAccount.getRole())) {
            throw new CustomException(ErrorCodeEnum.ONLY_USER_CREATE_POST);
        }
        return this.userService.lambdaQuery()
                .eq(User::getUsername, currentLoginAccount.getUsername())
                .one();
    }

    /**
     * 校验角色是否是管理员
     *
     */
    private void checkAdminRole() {
        Account currentLoginAccount = AccountUtils.getCurrentLoginAccount();
        if (currentLoginAccount == null) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        if (!RoleEnum.ADMIN.name().equals(currentLoginAccount.getRole())) {
            throw new CustomException(ErrorCodeEnum.ONLY_ADMIN_AUDIT_POST);
        }
    }
}
